package com.acme.bankapp.domain.bank;

import java.io.*;
import java.util.*;

import com.acme.bankapp.domain.exception.AccountNotFoundException;

/**
 * Class stores client information
 * @author alex
 */
@SuppressWarnings("serial")
public class Client implements Serializable, Cloneable {
	private String name;
	private Gender gender;
	private Map<Integer, Account> accounts;
	
	/**
	 * @param name the name
	 * @param gender the gender
	 */
	public Client(String name, Gender gender) {
		this.name = name;
		this.gender = gender;
		this.accounts = new HashMap<Integer, Account>();
	}
	
	/**
	 * @param name the name
	 * @param gender the gender
	 * @param account the account
	 */
	public Client(String name, Gender gender, Account account) {
		this(name, gender);
		this.addAccount(account);
	}
	
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * @return the gender
	 */
	public Gender getGender() {
		return gender;
	}
	/**
	 * @param accountId the account id
	 * @return the account
	 * @throws AccountNotFoundException 
	 */
	public Account getAccount(int accountId) throws AccountNotFoundException {
		if (this.accounts.containsKey(accountId))
			return this.accounts.get(accountId);
		else
			throw new AccountNotFoundException();
	}
	
	/**
	 * @param account the account
	 */
	public void addAccount(Account account) {
		this.accounts.put(((AbstractAccount) account).getAccountId(), account);
	}
	
	/**
	 * @return the account map
	 */
	public Map<Integer, Account> getAccounts() {
		Map<Integer, Account> immutable = new HashMap<Integer, Account>();
		for (Account account : this.accounts.values()) {
			try {
				immutable.put(((AbstractAccount) account).getAccountId(), ((Account) ((AbstractAccount) account).clone()));
			} catch (CloneNotSupportedException e) {
				System.out.println("Err: Clone not supported!");
			}
		}
		return immutable;
	}
	
	/**
	 * @return the accounts count
	 */
	public int getAccountsCount() {
		return this.accounts.size();
	}
	
	/**
	 * @return the string presentation
	 */
	@Override
	public String toString() {
		return this.gender.getSalutation() + this.name + "(" + this.accounts.size() + " account(s))";
	}
	
	/**
	 * @return the client object hash code
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((gender == null) ? 0 : gender.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	
	/**
	 * @param obj the client
	 * @return whether clients are equal
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Client other = (Client) obj;
		if (gender != other.gender)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	/**
	 * @return the client copy
	 */
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
